/*******************************************************************/
/*                                                                 */
/*  NAME    = send_pcap.h                                                   */
/*  NOTE    =                                                      */
/*  DATE    = 2014/12/10 by yinghl                                    */
/*******************************************************************/

#ifndef __SEND_PCAP_H__
#define __SEND_PCAP_H__

#include <pcap.h>
#include <libnet.h>
#include <net/ethernet.h>
#include <linux/ip.h>
#include <netinet/tcp.h>

#include <string>

class SendPcap
{
public:
    SendPcap(const std::string &pcap, uint32_t fps,
            libnet_t *libnet, const std::string &changePortCmpData, int changePort);
    ~SendPcap();

    void doSend();

private:
    void parsePcapData(u_int capLen, const u_char *pktData);
    bool parseEtherHeader(u_int capLen, const u_char *pktData,
            ether_header &ethHeader, u_int &linkOffset);
    bool parseIPHeader(u_int capLen, const u_char *pktData,
            u_int linkOffset, iphdr &ipHeader, const u_char **ipHeaderData);
    bool parseTCPHeader(u_int capLen, const u_char *pktData,
            u_int linkOffset, const iphdr &ipHeader,
            tcphdr &tcpHeader, const u_char **tcpHeaderData);
    int parseTCPDataLen(u_int capLen, u_int linkOffset,
            const iphdr &ipHeader, const tcphdr &tcpHeader);

    bool parseTCPProtol(u_int capLen, const u_char *pktData,
            u_int linkOffset, const ether_header &ethHeader,
            const iphdr &ipHeader);

    bool sendTCPProtol(const ether_header &ethHeader, const iphdr &ipHeader,
            const tcphdr &tcpHeader, const u_char *tcpOptionData, int tcpOptionLen,
            const u_char *tcpData, int tcpDataLen);
    bool buildTCPOptions(const u_char *tcpOptionData, int tcpOptionLen);
    bool buildTCPData(const tcphdr &tcpHeader, const u_char *tcpData, int tcpDataLen,
            int tcpOptionLen);
    bool buildIPv4(const iphdr &ipHeader, const u_char *ipData, int ipDataLen);
    bool buildEther(const ether_header &ethHeader);

    bool parseIPProtol(u_int capLen, const u_char *pktData,
            u_int linkOffset, const ether_header &ethHeader,
            const iphdr &ipHeader);
    int parseIPDataLen(u_int capLen, u_int linkOffset,
            const iphdr &ipHeader);
    bool sendIPProtol(const ether_header &ethHeader, const iphdr &ipHeader,
            const u_char *ipData, int ipDataLen);

    bool initLibNet();
    bool libNetWrite();

    bool needChangePort(const std::string &flag, uint32_t addr, int port);

private:
    std::string pcap_;
    pcap_t *pcapHandle_;
    libnet_t *libnetHandle_;
    uint32_t fps_;
    std::string changePortCmpData_;
    int changePort_;
};
#endif    // #ifndef __SEND_PCAP_H__

